package com.leyou.auth.service.impl;

import com.leyou.auth.config.JwtProperties;
import com.leyou.auth.service.AuthService;
import com.leyou.common.auth.entity.Payload;
import com.leyou.common.auth.entity.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.enums.LyExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.CookieUtils;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private UserClient userClient;

    @Autowired
    private JwtProperties prop;

    @Override
    public void login(String username, String password, HttpServletResponse response) {
        //1、调用用户中心，基于用户名和密码查询用户信息
        UserDTO user = userClient.queryUser(username, password);
        if(user==null){
            throw new LyException(LyExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        //2、如果用户存在，生成token
        UserInfo info = new UserInfo(user.getId(),user.getUsername(),"admin");
        //生成token
        createToken(response, info);

    }

    /**
     * 生成token
     * @param response
     * @param info
     */
    private void createToken(HttpServletResponse response, UserInfo info) {

        String token = JwtUtils.generateTokenExpireInMinutes(info, prop.getPrivateKey(), prop.getUser().getExpire());
        //3、将生成的token存入cookie返回客户端   path cookiename  cookiedomain  maxage
        CookieUtils.newCookieBuilder().response(response)  // response,用于写cookie
                .name(prop.getUser().getCookieName())
                .value(token)
                .domain(prop.getUser().getCookieDomain()) // 设置domain 域名
                .httpOnly(true) // 保证安全防止XSS攻击，不允许JS操作cookie
                .build();
    }

    @Override
    public UserInfo verify(HttpServletRequest request,HttpServletResponse response) {
        try {
            //1、获取token
            String token = CookieUtils.getCookieValue(request, prop.getUser().getCookieName());

            //2、解析token，获取载荷信息
            Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), UserInfo.class);
           //校验token时，需要从redis黑名单查看是否有当前token
            Boolean boo = redisTemplate.hasKey(payload.getId());
            if(boo!=null && boo){
                throw new LyException(LyExceptionEnum.UNAUTHORIZED);
            }
              /*但是如果30分钟内用户没有发送任何请求,则无法刷新token,则需要用户从新登陆
              * 或者"一开始"将token的过期时间设置的长一些*/

            //获取token过期时间
            Date expiration = payload.getExpiration();
            //3、将载荷中用户信息返回
            UserInfo userInfo = payload.getUserInfo();

            DateTime refreshTime = new DateTime(expiration.getTime()).minusMinutes(prop.getUser().getRefreshTime());
            //如果当前时间大于刷新时间时，生成新token
            if (refreshTime.isBefore(System.currentTimeMillis())) {
                createToken(response,userInfo);
            }
            return userInfo;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("【授权中心】，token解析失败",e);
            throw new LyException(LyExceptionEnum.UNAUTHORIZED);
        }


    }

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response) {

        try {
            //获取token
            String token = CookieUtils.getCookieValue(request, prop.getUser().getCookieName());
            //解析token
            Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), UserInfo.class);
            //将失效token的标记存入redis token黑名单
            long time = payload.getExpiration().getTime() - System.currentTimeMillis();
            String tokenId = payload.getId();

            if (time>3000) {
                redisTemplate.boundValueOps(tokenId).set("",time, TimeUnit.MILLISECONDS);
            }

            //删除cookie
            CookieUtils.deleteCookie(prop.getUser().getCookieName(),prop.getUser().getCookieDomain(),response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
